﻿#include "stdafx.h"
#include "sbhs.h"

#ifndef k_eq
#define k_eq(a,b)		(((a)+0.0001f>(b)) && ((a)-0.0001f<(b)))
#endif

//////////////////////////////////////////////////////////////////////////
// 널

static const char* _k_value_null_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	if (outlen)
		*outlen = 4;

	return k_syminstt("null");
}

static void _k_value_null_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		NULL,
		NULL,
		kh_op_supp_op_sig,
		NULL,
		NULL,
		NULL,

		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		kh_op_supp_op_beq,
		kh_op_supp_op_bne,
		NULL,
		NULL,
		NULL,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		kh_op_supp_op_new,
		_k_value_null_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 포인터

static const char* _k_value_ptr_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	int len = k_snprintf(buf, size, "{0x%p}", v->rv.p);

	if (outlen)
		*outlen = len;

	return buf;
}

static void _k_value_ptr_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		NULL,
		NULL,
		kh_op_supp_op_sig,
		NULL,
		NULL,
		NULL,

		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		kh_op_supp_op_beq,
		kh_op_supp_op_bne,
		NULL,
		NULL,
		NULL,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		kh_op_supp_op_new,
		_k_value_ptr_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 불

static const char* _k_value_bool_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	if (v->rv.i == FALSE)
	{
		buf = (char*)k_syminstt("false");

		if (outlen)
			*outlen = 5;
	}
	else
	{
		buf = (char*)k_syminstt("true");

		if (outlen)
			*outlen = 4;
	}

	return buf;
}

static int _k_value_bool_op_new(kVar* v, kint arity, kVar* args)
{
	if (arity != 1)
		k_var_set_bool(v, FALSE);
	else
	{
		kbool val;
		k_var_conv_bool(&args[0], &val);
		k_var_set_bool(v, val);
	}

	return 0;
}

static int _k_value_bool_op_sig(kVar* ops)
{
	ops[0].rv.i = !ops[0].rv.i;
	return 0;
}

static int _k_value_bool_op_beq(kVar* ops)
{
	ops[0].rv.i = ops[0].rv.i == ops[1].rv.i;
	return 0;
}

static int _k_value_bool_op_bne(kVar* ops)
{
	ops[0].rv.i = ops[0].rv.i != ops[1].rv.i;
	return 0;
}

static void _k_value_bool_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		NULL,
		NULL,
		_k_value_bool_op_sig,
		NULL,
		NULL,
		NULL,

		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		_k_value_bool_op_beq,
		_k_value_bool_op_bne,
		NULL,
		NULL,
		NULL,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		_k_value_bool_op_new,
		_k_value_bool_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 정수

static const char* _k_value_int_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	int len = k_snprintf(buf, size, "%d", v->rv.i);

	if (outlen)
		*outlen = len;

	return buf;
}

static int _k_value_int_op_new(kVar* v, kint arity, kVar* args)
{
	if (arity != 1)
		k_var_set_int(v, 0);
	else
	{
		int val;
		k_var_conv_int(&args[0], &val);
		k_var_set_int(v, val);
	}

	return 0;
}

static int _k_value_int_op_pos(kVar* ops)
{
	return 0;
}

static int _k_value_int_op_neg(kVar* ops)
{
	ops[0].rv.i = -ops[0].rv.i;
	return 0;
}

static int _k_value_int_op_sig(kVar* ops)
{
	ops[0].rv.i = !ops[0].rv.i;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_int_op_not(kVar* ops)
{
	ops[0].rv.i = ~ops[0].rv.i;
	return 0;
}

static int _k_value_int_op_inc(kVar* ops)
{
	ops[0].rv.i++;
	return 0;
}

static int _k_value_int_op_dec(kVar* ops)
{
	ops[0].rv.i--;
	return 0;
}

static int _k_value_int_op_mul(kVar* ops)
{
	ops[0].rv.i *= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_div(kVar* ops)
{
	ops[0].rv.i /= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_mod(kVar* ops)
{
	ops[0].rv.i %= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_add(kVar* ops)
{
	ops[0].rv.i += ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_sub(kVar* ops)
{
	ops[0].rv.i -= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_shl(kVar* ops)
{
	ops[0].rv.i <<= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_shr(kVar* ops)
{
	ops[0].rv.i >>= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_blt(kVar* ops)
{
	ops[0].rv.i = ops[0].rv.i < ops[1].rv.i;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_int_op_ble(kVar* ops)
{
	ops[0].rv.i = ops[0].rv.i <= ops[1].rv.i;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_int_op_beq(kVar* ops)
{
	ops[0].rv.i = ops[0].rv.i == ops[1].rv.i;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_int_op_bne(kVar* ops)
{
	ops[0].rv.i = ops[0].rv.i != ops[1].rv.i;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_int_op_and(kVar* ops)
{
	ops[0].rv.i &= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_xor(kVar* ops)
{
	ops[0].rv.i ^= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static int _k_value_int_op_or(kVar* ops)
{
	ops[0].rv.i |= ops[1].rv.i;
	ops[0].type = KTYPE_INT;
	return 0;
}

static void _k_value_int_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		_k_value_int_op_pos,
		_k_value_int_op_neg,
		_k_value_int_op_sig,
		_k_value_int_op_not,
		_k_value_int_op_inc,
		_k_value_int_op_dec,

		_k_value_int_op_mul,
		_k_value_int_op_div,
		_k_value_int_op_mod,
		_k_value_int_op_add,
		_k_value_int_op_sub,
		_k_value_int_op_shl,
		_k_value_int_op_shr,
		_k_value_int_op_blt,
		_k_value_int_op_ble,
		_k_value_int_op_beq,
		_k_value_int_op_bne,
		_k_value_int_op_and,
		_k_value_int_op_xor,
		_k_value_int_op_or,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		_k_value_int_op_new,
		_k_value_int_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 실수

static const char* _k_value_float_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	int len = k_snprintf(buf, size, "%f", v->rv.f);

	if (outlen)
		*outlen = len;

	return buf;
}

static int _k_value_float_op_new(kVar* v, kint arity, kVar* args)
{
	if (arity != 1)
		k_var_set_float(v, 0.0f);
	else
	{
		float val;
		k_var_conv_float(&args[0], &val);
		k_var_set_float(v, val);
	}

	return 0;
}

static float _k_value_float_op_value(const kVar* p)
{
	switch (p->type)
	{
		case KTYPE_FLOAT:
			return p->rv.f;

		case KTYPE_NULL:
			return 0.0f;

		case KTYPE_BOOL:
		case KTYPE_INT:
			return (float)p->rv.i;

		case KTYPE_LONG:
			return (float)p->rv.i64;

#if 0
		case KTYPE_DOUBLE:
			return (float)p->rv.dbl;
#endif
	}

	return 0.0f;
}

static int _k_value_float_op_pos(kVar* ops)
{
	return 0;
}

static int _k_value_float_op_neg(kVar* ops)
{
	ops[0].rv.f = -ops[0].rv.f;
	return 0;
}

static int _k_value_float_op_sig(kVar* ops)
{
	ops[0].rv.i = k_eq(ops[0].rv.f, 0.0f) ? 1 : 0;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_float_op_inc(kVar* ops)
{
	ops[0].rv.f += 1.0f;
	return 0;
}

static int _k_value_float_op_dec(kVar* ops)
{
	ops[0].rv.f -= 1.0f;
	return 0;
}

static int _k_value_float_op_mul(kVar* ops)
{
	ops[0].rv.f = _k_value_float_op_value(&ops[0]) * _k_value_float_op_value(&ops[1]);
	ops[0].type = KTYPE_FLOAT;
	return 0;
}

static int _k_value_float_op_div(kVar* ops)
{
	ops[0].rv.f = _k_value_float_op_value(&ops[0]) / _k_value_float_op_value(&ops[1]);
	ops[0].type = KTYPE_FLOAT;
	return 0;
}

static int _k_value_float_op_mod(kVar* ops)
{
	ops[0].rv.f = fmodf(_k_value_float_op_value(&ops[0]), _k_value_float_op_value(&ops[1]));
	ops[0].type = KTYPE_FLOAT;
	return 0;
}

static int _k_value_float_op_add(kVar* ops)
{
	ops[0].rv.f = _k_value_float_op_value(&ops[0]) + _k_value_float_op_value(&ops[1]);
	ops[0].type = KTYPE_FLOAT;
	return 0;
}

static int _k_value_float_op_sub(kVar* ops)
{
	ops[0].rv.f = _k_value_float_op_value(&ops[0]) - _k_value_float_op_value(&ops[1]);
	ops[0].type = KTYPE_FLOAT;
	return 0;
}

static int _k_value_float_op_blt(kVar* ops)
{
	ops[0].rv.i = _k_value_float_op_value(&ops[0]) < _k_value_float_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_float_op_ble(kVar* ops)
{
	ops[0].rv.i = _k_value_float_op_value(&ops[0]) <= _k_value_float_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_float_op_beq(kVar* ops)
{
	float l = _k_value_float_op_value(&ops[0]);
	float r = _k_value_float_op_value(&ops[1]);
	ops[0].rv.i = k_eq(l, r) ? 1 : 0;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_float_op_bne(kVar* ops)
{
	float l = _k_value_float_op_value(&ops[0]);
	float r = _k_value_float_op_value(&ops[1]);
	ops[0].rv.i = k_eq(l, r) ? 0 : 1;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static void _k_value_float_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		_k_value_float_op_pos,
		_k_value_float_op_neg,
		_k_value_float_op_sig,
		NULL,
		_k_value_float_op_inc,
		_k_value_float_op_dec,

		_k_value_float_op_mul,
		_k_value_float_op_div,
		_k_value_float_op_mod,
		_k_value_float_op_add,
		_k_value_float_op_sub,
		NULL,
		NULL,
		_k_value_float_op_blt,
		_k_value_float_op_ble,
		_k_value_float_op_beq,
		_k_value_float_op_bne,
		NULL,
		NULL,
		NULL,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		_k_value_float_op_new,
		_k_value_float_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 긴 정수

static const char* _k_value_long_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	int len = k_snprintf(buf, size, "%lld", v->rv.i64);

	if (outlen)
		*outlen = len;

	return buf;
}

static int _k_value_long_op_new(kVar* v, kint arity, kVar* args)
{
	if (arity != 1)
		k_var_set_long(v, 0);
	else
	{
		klong val;
		k_var_conv_long(&args[0], &val);
		k_var_set_long(v, val);
	}

	return 0;
}

static klong _k_value_long_op_value(const kVar* p)
{
	switch (p->type)
	{
		case KTYPE_LONG:
			return p->rv.i64;

		case KTYPE_NULL:
			return 0;

		case KTYPE_BOOL:
		case KTYPE_INT:
			return p->rv.i;

#if 0
		case KTYPE_FLOAT:
			return (klong)p->rv.i64;

		case KTYPE_DOUBLE:
			return (klong)p->rv.dbl;
#endif
	}

	return 0;
}

static int _k_value_long_op_pos(kVar* ops)
{
	return 0;
}

static int _k_value_long_op_neg(kVar* ops)
{
	ops[0].rv.i64 = -ops[0].rv.i64;
	return 0;
}

static int _k_value_long_op_sig(kVar* ops)
{
	ops[0].rv.i = !ops[0].rv.i64;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_long_op_not(kVar* ops)
{
	ops[0].rv.i64 = ~ops[0].rv.i64;
	return 0;
}

static int _k_value_long_op_inc(kVar* ops)
{
	ops[0].rv.i64++;
	return 0;
}

static int _k_value_long_op_dec(kVar* ops)
{
	ops[0].rv.i64--;
	return 0;
}

static int _k_value_long_op_mul(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) * _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_div(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) * _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_mod(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) % _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_add(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) + _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_sub(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) - _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_shl(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) << _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_shr(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) >> _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_blt(kVar* ops)
{
	ops[0].rv.i = _k_value_long_op_value(&ops[0]) < _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_long_op_ble(kVar* ops)
{
	ops[0].rv.i = _k_value_long_op_value(&ops[0]) <= _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_long_op_beq(kVar* ops)
{
	ops[0].rv.i = _k_value_long_op_value(&ops[0]) == _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_long_op_bne(kVar* ops)
{
	ops[0].rv.i = _k_value_long_op_value(&ops[0]) != _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_long_op_and(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0])&_k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_xor(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) ^ _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static int _k_value_long_op_or(kVar* ops)
{
	ops[0].rv.i64 = _k_value_long_op_value(&ops[0]) | _k_value_long_op_value(&ops[1]);
	ops[0].type = KTYPE_LONG;
	return 0;
}

static void _k_value_long_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		_k_value_long_op_pos,
		_k_value_long_op_neg,
		_k_value_long_op_sig,
		_k_value_long_op_not,
		_k_value_long_op_inc,
		_k_value_long_op_dec,

		_k_value_long_op_mul,
		_k_value_long_op_div,
		_k_value_long_op_mod,
		_k_value_long_op_add,
		_k_value_long_op_sub,
		_k_value_long_op_shl,
		_k_value_long_op_shr,
		_k_value_long_op_blt,
		_k_value_long_op_ble,
		_k_value_long_op_beq,
		_k_value_long_op_bne,
		_k_value_long_op_and,
		_k_value_long_op_xor,
		_k_value_long_op_or,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		_k_value_long_op_new,
		_k_value_long_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 실수

static const char* _k_value_double_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	int len = k_snprintf(buf, size, "%f", v->rv.dbl);

	if (outlen)
		*outlen = len;

	return buf;
}

static int _k_value_double_op_new(kVar* v, kint arity, kVar* args)
{
	if (arity != 1)
		k_var_set_double(v, 0.0);
	else
	{
		double val;
		k_var_conv_double(&args[0], &val);
		k_var_set_double(v, val);
	}

	return 0;
}

static double _k_value_double_op_value(const kVar* p)
{
	switch (p->type)
	{
		case KTYPE_DOUBLE:
			return p->rv.dbl;

		case KTYPE_FLOAT:
			return p->rv.f;

		case KTYPE_NULL:
			return 0;

		case KTYPE_BOOL:
		case KTYPE_INT:
			return p->rv.i;

		case KTYPE_LONG:
			return (double)p->rv.i64;
	}

	return 0.0;
}

static int _k_value_double_op_pos(kVar* ops)
{
	return 0;
}

static int _k_value_double_op_neg(kVar* ops)
{
	ops[0].rv.dbl = -ops[0].rv.dbl;
	return 0;
}

static int _k_value_double_op_sig(kVar* ops)
{
	ops[0].rv.i = k_eq(ops[0].rv.dbl, 0.0f) ? 1 : 0;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_double_op_inc(kVar* ops)
{
	ops[0].rv.dbl += 1.0;
	return 0;
}

static int _k_value_double_op_dec(kVar* ops)
{
	ops[0].rv.dbl -= 1.0;
	return 0;
}

static int _k_value_double_op_mul(kVar* ops)
{
	ops[0].rv.dbl = _k_value_double_op_value(&ops[0]) * _k_value_double_op_value(&ops[1]);
	ops[0].type = KTYPE_DOUBLE;
	return 0;
}

static int _k_value_double_op_div(kVar* ops)
{
	ops[0].rv.dbl = _k_value_double_op_value(&ops[0]) / _k_value_double_op_value(&ops[1]);
	ops[0].type = KTYPE_DOUBLE;
	return 0;
}

static int _k_value_double_op_mod(kVar* ops)
{
	ops[0].rv.dbl = fmod(_k_value_double_op_value(&ops[0]), _k_value_double_op_value(&ops[1]));
	ops[0].type = KTYPE_DOUBLE;
	return 0;
}

static int _k_value_double_op_add(kVar* ops)
{
	ops[0].rv.dbl = _k_value_double_op_value(&ops[0]) + _k_value_double_op_value(&ops[1]);
	ops[0].type = KTYPE_DOUBLE;
	return 0;
}

static int _k_value_double_op_sub(kVar* ops)
{
	ops[0].rv.dbl = _k_value_double_op_value(&ops[0]) - _k_value_double_op_value(&ops[1]);
	ops[0].type = KTYPE_DOUBLE;
	return 0;
}

static int _k_value_double_op_blt(kVar* ops)
{
	ops[0].rv.i = _k_value_double_op_value(&ops[0]) < _k_value_double_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_double_op_ble(kVar* ops)
{
	ops[0].rv.i = _k_value_double_op_value(&ops[0]) <= _k_value_double_op_value(&ops[1]);
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_double_op_beq(kVar* ops)
{
	double l = _k_value_double_op_value(&ops[0]);
	double r = _k_value_double_op_value(&ops[1]);
	ops[0].rv.i = k_eq(l, r) ? 1 : 0;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static int _k_value_double_op_bne(kVar* ops)
{
	double l = _k_value_double_op_value(&ops[0]);
	double r = _k_value_double_op_value(&ops[1]);
	ops[0].rv.i = k_eq(l, r) ? 0 : 1;
	ops[0].type = KTYPE_BOOL;
	return 0;
}

static void _k_value_double_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		_k_value_double_op_pos,
		_k_value_double_op_neg,
		_k_value_double_op_sig,
		NULL,
		_k_value_double_op_inc,
		_k_value_double_op_dec,

		_k_value_double_op_mul,
		_k_value_double_op_div,
		_k_value_double_op_mod,
		_k_value_double_op_add,
		_k_value_double_op_sub,
		NULL,
		NULL,
		_k_value_double_op_blt,
		_k_value_double_op_ble,
		_k_value_double_op_beq,
		_k_value_double_op_bne,
		NULL,
		NULL,
		NULL,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		_k_value_double_op_new,
		_k_value_double_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 심볼

static const char* _k_value_sym_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	kuint s = v->rv.u;

	if (outlen)
		*outlen = (kint)k_symunlen(s);

	return k_symunstr(s);
}

static int _k_value_sym_op_new(kVar* v, kint arity, kVar* args)
{
	if (arity != 1)
		k_var_set_sym(v, 0);
	else
	{
		char buf[64];
		const char* psz = k_var_tos(&args[0], buf, 64, NULL);
		k_var_set_sym_flex(v, psz);
	}

	return 0;
}

static const char* _k_value_sym_op_value(const kVar* v, char* buf, kint size, kint* outlen, kVar* save)
{
	k_var_agn(save, v);
	return k_var_tos(v, buf, size, outlen);
}

static int _k_value_sym_op_sig(kVar* ops)
{
	k_var_unload(&ops[0]);
	ops[0].type = KTYPE_BOOL;
	ops[0].rv.i = 0;
	return 0;
}

static int _k_value_sym_op_add(kVar* ops)
{
	kVar save[2];
	char str[2][64];
	kint len[3];
	const char* psz[2];
	char* sz;

	psz[0] = _k_value_sym_op_value(&ops[0], str[0], 64, &len[0], &save[0]);
	psz[1] = _k_value_sym_op_value(&ops[1], str[1], 64, &len[1], &save[1]);

	len[2] = len[0] + len[1];
	sz = (char*)alloca(len[2] + 1);

	memcpy(sz, psz[0], len[0]);
	memcpy(sz + len[0], psz[1], len[1]);
	sz[len[2]] = '\0';

#if 0
	// 심볼에 심볼을 더하면 새 심볼이 된다
	// 심볼로
	k_var_set_sym_flex(&ops[0], sz);
#else
	// 심볼에 심볼을 더하니 문자열이 되부릿네
	// 문자열로
	k_var_set_str(&ops[0], sz, len[2]);
#endif

	k_var_unload(&save[0]);
	k_var_unload(&save[1]);

	return 0;
}

static int _k_value_sym_op_blt(kVar* ops)
{
	kVar save[2];
	char str[2][64];
	const char* psz[2];

	psz[0] = _k_value_sym_op_value(&ops[0], str[0], 64, NULL, &save[0]);
	psz[1] = _k_value_sym_op_value(&ops[1], str[1], 64, NULL, &save[1]);

	k_var_set_bool(&ops[0], k_strcmp(psz[0], psz[1]) == -1 ? TRUE : FALSE);

	k_var_unload(&save[0]);
	k_var_unload(&save[1]);

	return 0;
}

static int _k_value_sym_op_ble(kVar* ops)
{
	kVar save[2];
	char str[2][64];
	const char* psz[2];

	psz[0] = _k_value_sym_op_value(&ops[0], str[0], 64, NULL, &save[0]);
	psz[1] = _k_value_sym_op_value(&ops[1], str[1], 64, NULL, &save[1]);

	k_var_set_bool(&ops[0], k_strcmp(psz[0], psz[1]) == 1 ? TRUE : FALSE);

	k_var_unload(&save[0]);
	k_var_unload(&save[1]);

	return 0;
}

static int _k_value_sym_op_beq(kVar* ops)
{
	kVar save[2];
	char str[2][64];
	const char* psz[2];

	psz[0] = _k_value_sym_op_value(&ops[0], str[0], 64, NULL, &save[0]);
	psz[1] = _k_value_sym_op_value(&ops[1], str[1], 64, NULL, &save[1]);

	k_var_set_bool(&ops[0], k_strcmp(psz[0], psz[1]) == 0 ? TRUE : FALSE);

	k_var_unload(&save[0]);
	k_var_unload(&save[1]);

	return 0;
}

static int _k_value_sym_op_bne(kVar* ops)
{
	kVar save[2];
	char str[2][64];
	const char* psz[2];

	psz[0] = _k_value_sym_op_value(&ops[0], str[0], 64, NULL, &save[0]);
	psz[1] = _k_value_sym_op_value(&ops[1], str[1], 64, NULL, &save[1]);

	k_var_set_bool(&ops[0], k_strcmp(psz[0], psz[1]) == 0 ? TRUE : FALSE);

	k_var_unload(&save[0]);
	k_var_unload(&save[1]);

	return 0;
}

static int _k_value_sym_op_ldv(kVar* ops)
{
	if (!k_var_is_int(&ops[1]))
	{
		// 기본
		return kh_op_supp_ldv(KTYPE_SYMBOL, &ops[0], &ops[1], &ops[0]);
	}
	else
	{
		// 인덱스
		const char* psz;
		ksize_t len, index = ops[1].rv.i;
		k_symunvalue(ops[0].rv.u, &psz, &len);

		if (index >= len)
			k_var_zero(&ops[0]);
		else
			k_var_set_int(&ops[0], psz[index]);

		return 0;
	}
}

static void _k_value_sym_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		NULL,
		NULL,
		_k_value_sym_op_sig,
		NULL,
		NULL,
		NULL,

		NULL,
		NULL,
		NULL,
		_k_value_sym_op_add,
		NULL,
		NULL,
		NULL,
		_k_value_sym_op_blt,
		_k_value_sym_op_ble,
		_k_value_sym_op_beq,
		_k_value_sym_op_bne,
		NULL,
		NULL,
		NULL,

		NULL,
		_k_value_sym_op_ldv,

		_k_value_sym_op_new,
		_k_value_sym_op_tos,
	};

	k_type_set_optable(type, &optbl);
}


//////////////////////////////////////////////////////////////////////////
// 파라미터 함수

static const char* _k_value_prm_op_tos(const kVar* v, char* buf, kint size, kint* outlen)
{
	khParamDesc* param = (khParamDesc*)v->rv.p;
	kint len;

	if (param->prm == KHPRM_VAR)
	{
		k_halt_impl("hb.value.param");
		len = 0;
	}
	else if (param->prm == KHPRM_PROP)
	{
		struct khParamPropDesc* prop = (struct khParamPropDesc*)param;
		len = k_snprintf(buf, size, "<P:%s, %s:%u>", param->name, k_type_get_name(param->type), prop->offset);
	}
	else if (param->prm == KHPRM_FUNC)
	{
		struct khParamFuncDesc* func = (struct khParamFuncDesc*)param;
		len = k_snprintf(buf, size, "<F:%s, 0x%p>", param->name, func->func);
	}
	else
	{
		len = k_snprintf(buf, size, "<U:%d>", param->type);
	}

	if (outlen)
		*outlen = len;

	return buf;
}

static void _k_value_prm_type_init(kType type)
{
	static struct khOpTable optbl =
	{
		NULL,

		NULL,
		NULL,
		kh_op_supp_op_sig,
		NULL,
		NULL,
		NULL,

		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		kh_op_supp_op_beq,
		kh_op_supp_op_bne,
		NULL,
		NULL,
		NULL,

		kh_op_supp_op_stv,
		kh_op_supp_op_ldv,

		NULL,
		_k_value_prm_op_tos,
	};

	k_type_set_optable(type, &optbl);
}

//
void _k_type_value_init()
{
	kTypeDecl desc = {0, KTIF_VALUE, NULL, NULL, NULL, NULL};

	// null
	desc.size = 0;
	desc.type_init = _k_value_null_type_init;
	k_tmnt_reg_red((kuint)KTYPE_NULL, "Null", &desc, 0);

	// paramter
	desc.size = sizeof(khParamDesc*);
	desc.type_init = _k_value_prm_type_init;
	k_tmnt_reg_red((kuint)KTYPE_PARAM, "Parameter", &desc, 0);

	// pointer
	desc.size = sizeof(kpointer);
	desc.type_init = _k_value_ptr_type_init;
	k_tmnt_reg_red((kuint)KTYPE_POINTER, "Pointer", &desc, 0);

	// symbol
	desc.size = sizeof(kuint);
	desc.type_init = _k_value_sym_type_init;
	k_tmnt_reg_red((kuint)KTYPE_SYMBOL, "Symbol", &desc, 0);

	// bool
	desc.size = sizeof(kbool);
	desc.type_init = _k_value_bool_type_init;
	k_tmnt_reg_red((kuint)KTYPE_BOOL, "Bool", &desc, 0);

	// int
	desc.size = sizeof(int);
	desc.type_init = _k_value_int_type_init;
	k_tmnt_reg_red((kuint)KTYPE_INT, "Int", &desc, 0);

	// long
	desc.size = sizeof(klong);
	desc.type_init = _k_value_long_type_init;
	k_tmnt_reg_red((kuint)KTYPE_LONG, "Long", &desc, 0);

	// float
	desc.size = sizeof(float);
	desc.type_init = _k_value_float_type_init;
	k_tmnt_reg_red((kuint)KTYPE_FLOAT, "Float", &desc, 0);

	// double
	desc.size = sizeof(double);
	desc.type_init = _k_value_double_type_init;
	k_tmnt_reg_red((kuint)KTYPE_DOUBLE, "Double", &desc, 0);
}
